package com.fzs.sshd.util;
import lombok.extern.slf4j.Slf4j;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class AdbParser {

    // ADB 协议常量
    public static final int ADB_SYNC = 0x434e5953;
    public static final int ADB_CNXN = 0x4e584e43;
    public static final int ADB_AUTH = 0x48545541;
    public static final int ADB_OPEN = 0x4e45504f;
    public static final int ADB_OKAY = 0x59414b4f;
    public static final int ADB_CLSE = 0x45534c43;
    public static final int ADB_WRTE = 0x45545257;
    public static final int ADB_FAIL = 0x4c494146;
    public static final int ADB_EXEC = 0x43455845;

    // 映射 command -> 字符串
    private static final Map<Integer, String> commandMap = Map.ofEntries(
            Map.entry(ADB_SYNC, "SYNC"),
            Map.entry(ADB_CNXN, "CNXN"),
            Map.entry(ADB_AUTH, "AUTH"),
            Map.entry(ADB_OPEN, "OPEN"),
            Map.entry(ADB_OKAY, "OKAY"),
            Map.entry(ADB_CLSE, "CLSE"),
            Map.entry(ADB_WRTE, "WRTE"),
            Map.entry(ADB_FAIL, "FAIL"),
            Map.entry(ADB_EXEC, "EXEC")
    );

    // ADB 消息头
    public static class AdbMessage {
        public int command;
        public int arg0;
        public int arg1;
        public int dataLength;
        public int dataCheck;
        public int magic;
        public byte[] payload;

        public String commandString() {
            return commandMap.getOrDefault(command, "UNKNOWN(0x" + Integer.toHexString(command) + ")");
        }
    }

    // 解析 ADB 数据流
    public static List<AdbMessage> parse(byte[] data) {
        List<AdbMessage> messages = new ArrayList<>();
        int offset = 0;

        while (offset + 24 <= data.length) {
            ByteBuffer buf = ByteBuffer.wrap(data, offset, 24).order(ByteOrder.LITTLE_ENDIAN);
            AdbMessage msg = new AdbMessage();
            msg.command = buf.getInt();
            msg.arg0 = buf.getInt();
            msg.arg1 = buf.getInt();
            msg.dataLength = buf.getInt();
            msg.dataCheck = buf.getInt();
            msg.magic = buf.getInt();

            // 校验 magic
            if (msg.magic != (~msg.command)) {
                offset++; // 错位可能，尝试下一个字节
                continue;
            }

            if (!commandMap.containsKey(msg.command)){
                break;
            }

            // 非法长度，防止越界
            if (msg.dataLength < 0) {
                log.warn("invalid dataLength: {}, skip parsing", msg.dataLength);
                break;
            }

            offset += 24;
            if (offset + msg.dataLength > data.length) break;

            msg.payload = Arrays.copyOfRange(data, offset, offset + msg.dataLength);
            offset += msg.dataLength;

            messages.add(msg);
        }

        return messages;
    }

    // 提取可能的命令
    public static List<String> extractCommands(AdbMessage msg) {
        List<String> results = new ArrayList<>();
        byte[] payload = msg.payload;
        if (!commandMap.containsKey(msg.command) || payload == null || payload.length == 0) {
            return results;
        }



        String payloadStr = new String(payload, StandardCharsets.UTF_8);

        Pattern p = Pattern.compile("[a-zA-Z0-9_/-]+");
        Matcher m = p.matcher(payloadStr);

        while (m.find()) {
            String token = m.group();
            results.add(token);
        }
        return results;
    }


    private static boolean isCommonNonCommand(String s) {
        String[] common = {"shell", "v2", "pty", "OKAY", "WRTE", "OPEN", "CLSE",
                "android", "system", "bin", "dev", "proc", "sys"};
        return Arrays.asList(common).contains(s);
    }

    // 调试打印
    public static void printMessage(AdbMessage msg) {
        System.out.printf("[ADB] %s arg0=0x%x arg1=0x%x data_len=%d\n",
                msg.commandString(), msg.arg0, msg.arg1, msg.dataLength);

        if (msg.command == ADB_WRTE && msg.payload != null) {
            String payloadStr = isPrintable(msg.payload) ?
                    new String(msg.payload) : (msg.payload.length + " bytes binary");
            System.out.println("Payload: " + payloadStr);

            List<String> cmds = extractCommands(msg);
            if (!cmds.isEmpty()) {
                System.out.println("Extracted commands: " + cmds);
            }
        }
    }

    private static boolean isPrintable(byte[] data) {
        int printableCount = 0;
        for (byte b : data) {
            if ((b >= 32 && b <= 126) || b == '\n' || b == '\r' || b == '\t') {
                printableCount++;
            }
        }
        return data.length > 0 && (float) printableCount / data.length > 0.7;
    }
}
